﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.Xna.Framework;
using MobMentality.Map;
using MobMentality.GraphUtil;
using Microsoft.Xna.Framework.Graphics;
using MobMentality.Social.People;
using Microsoft.Xna.Framework.Content;

namespace MobMentality.Social
{
	class GroupController : IGroupController
	{
		/*Controller Constants*/
		public int INCITER_COOLDOWN
		{
			get
			{
				return 60 * 3;	//60 frames per second -> 10 seconds
			}
		}

		public int DISTRACTION_LIMIT
		{
			get
			{
				return 10;
			}
		}

		/*Group Info*/
		string groupName;
		Color groupColor;
		Team team;
		bool inciterSelected;

		float distracted;

		/*Members of this group*/
		List<Person> members;
		Inciter inciter;
		
		/*Navigation*/
		IMapNavigate navigationMap;
		Point targetTile;

        public List<Person> Members
        {
            get { return members; }
        }

		public GroupController(string GroupName, Color GroupColor, IMapNavigate navigationMap, Vector2 inciterMapLocation, Team team, ContentManager content)
		{
			groupName = GroupName;
			groupColor = GroupColor;
			members = new List<Person>();
			this.team = team;

			if (team != Team.Unconverted)
			{
				inciter = new Inciter(this, inciterMapLocation, INCITER_COOLDOWN, content);
				PeopleHolder.Instance.AddPerson(inciter);
				this.targetTile = navigationMap.GetTile(inciter.MapPosition);
			}
			else
			{
				inciter = null;
			}
			this.navigationMap = navigationMap;
			this.distracted = 0;
		}

		public void DirectAddMember(Person newMember)
		{
			members.Add(newMember);
		}

		public  string GroupName
		{
			get { return groupName; }
		}

		public Color GroupColor
		{
			get { return groupColor; }
		}

		public Team Team
		{
			get
			{
				return team;
			}
		}

		public bool IsInciterSelected
		{
			get { return inciterSelected; }
		}

		public float Distracted
		{
			get
			{
				return distracted;
			}
		}

		public int NumMembers
		{
			get
			{
				return members.Count;
			}
		}

		public void Command(Vector2 mapPosition)
		{
			List<Person> selection = PeopleHolder.Instance.PeopleInArea(mapPosition, 15);

			GoalLocation(mapPosition);
		}

		public void GoalLocation(Vector2 mapPosition)
		{
			targetTile = navigationMap.GetTile(mapPosition);
		}

		public void AddPerson(PersonType type)
		{
			inciter.AddConvertee(type);
		}

		public void ClearInciter()
		{
			inciter.clearConvertees();
		}

		private void AddPerson(Person newMember)
		{
			/*TODO
			 * move inciter to target person
			 * once inciter gets there, wait, display ... over inciter?
			 * after wait, add person
			 */

			//for now, just add them
			newMember.JoinGroup(this);
			members.Add(newMember);
			//convertee = null;
		}

		public void RemoveMember(Person person)
		{
			members.Remove(person);
		}

		public void UpdateGoals(bool attack)
		{
			/*Remove Dead People*/
			members.RemoveAll(p => p.Health <= 0);

			/*Do Healing*/
			/*Lol, not the best place for this but whatevs we have like 3 days left*/
			int healers = members.Count(p => p.Type == PersonType.Healer);

			foreach (Person member in members)
			{
				if (member.Health < 100)
				{
					member.Heal(healers);
				}
			}

			/*FIND HOW DISTRACTED THIS GROUP IS*/
			distracted = 0;
			foreach (Person member in members)
			{
				distracted = distracted + member.Unruly + member.Angry - member.Scared;
			}

			if (team != Team.Unconverted)
			{
				/*UPDATE THE INCITER*/
				Person toBeConverted = inciter.Update(navigationMap, targetTile);
				if (toBeConverted != null)
				{
					AddPerson(toBeConverted);
				}
			}

			/*UPDATE EVERYONE ELSE*/
			foreach (Person member in members)
			{
				Point currentTile = navigationMap.GetTile(member.MapPosition);
				Point currentTarget = targetTile;

				if (distracted > DISTRACTION_LIMIT)
				{
					List<Person> distractingEnemies = PeopleHolder.Instance.EnemiesNearby(member.MapPosition, team, navigationMap.TileWidth * (distracted/3));
					if (distractingEnemies.Count > 0)
					{
						member.SetTargetLocation(distractingEnemies.First().MapPosition);
						currentTarget = navigationMap.GetTile(distractingEnemies.First().MapPosition);
					}
					else if(team == Team.Riot)	//only the riot is distracted by looting
					{
						Point distractionTarget = navigationMap.NearestDistraction(currentTile);
						if (distractionTarget.X != -1 && distractionTarget.Y != -1)
						{
							//if (navigationMap.AStarDistance(currentTile, distractionTarget, delegate(Point point1, Point point2) { return (point2.X - point1.X) + (point2.Y - point1.Y); }) < 3)
							if((distractionTarget.X - currentTile.X) + (distractionTarget.Y - currentTile.Y) < 3)
							{
								currentTarget = distractionTarget;
							}
						}
					}
				}

				//Vector2 distanceFromTarget = navigationMap.GetMapPosition(currentTarget) - member.MapPosition + new Vector2(navigationMap.TileWidth / 2, navigationMap.TileHeight / 2);

				if((currentTile.X == member.nextTile.X || currentTile.X == member.nextTile.Y) || 
					(currentTile.X != currentTarget.X || currentTile.X != currentTarget.Y))
				{
					member.nextTile = navigationMap.nextAStarTile(currentTile, currentTarget, delegate(Point point1, Point point2) { return (point2.X - point1.X) + (point2.Y - point1.Y); });
				}
				
				//-1,-1 if there is no such path
				if (member.nextTile.X != -1 && member.nextTile.Y != -1)
				{
					Vector2 favoritePosition = new Vector2(member.favoriteSubPosition.X * (navigationMap.TileWidth / 3) + (navigationMap.TileWidth / 3) / 2,
															member.favoriteSubPosition.Y * (navigationMap.TileHeight / 3) + (navigationMap.TileWidth / 3) / 2);
					member.SetTargetLocation(navigationMap.GetMapPosition(member.nextTile, favoritePosition));
				}

				if (attack)
				{
					List<Person> enemiesNearby = PeopleHolder.Instance.EnemiesNearby(member.MapPosition, team, member.Width / 2 + member.Range);
					if (enemiesNearby.Count > 0)
					{
						member.Attack(enemiesNearby[0]);
					}
				}
			}
		}

		public bool OnClick(Vector2 clickPosition)
		{
			if (team == Team.Riot)
			{
				List<Person> selected = PeopleHolder.Instance.PeopleInArea(clickPosition, 15);

				inciterSelected = (selected.Count(p => p.Type == PersonType.Inciter) > 0);

				return true;
			}

			return false;
		}

        public bool OnNetClick(Vector2 clickPosition)
        {
            if (team == Team.Police)
            {
                List<Person> selected = PeopleHolder.Instance.PeopleInArea(clickPosition, 15);

                inciterSelected = (selected.Count(p => p.Type == PersonType.Inciter) > 0);

                return true;
            }

            return false;
        }
	}
}
